package pl.ps.wi.monitoring.station.services;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Timer;
import java.util.TimerTask;

import pl.ps.wi.monitoring.station.LocalConfiuration;
import pl.ps.wi.monitoring.station.enums.DataType;
import pl.ps.wi.monitoring.station.interfaces.DataCollector;

/** 
* @date 2010.05.12
* @version 1.00.00
*
* @brief Klasa odpowiedzialna za czujniki temperatury. Zawiera definicję klasy TemperatureService. 

* Klasa zawiera metody zwracające informacje o temperaturze oraz metody rozpoczynające oraz kończące wątek odpowiedzialny za pracę czujników temperatury
* Klasa implementuje interfejs DataCollector.
*/

public class TemperatureService implements DataCollector {
	
/**
* Zmienna String volatile zawierające dane, które
* muszą być za każdym razem aktualizowane do zmiennej.
*/
    private volatile String data;
	
/**
* Zmienna typu int przechowująca numer indexu czujnika
*/
    int index;
	
/**
* Zmienna typu String przechowująca aktualną komendę Unix'ową służącą do pomiaru temperatury
*/
    private String shellCommand;
	
/**
* Zmienna typu Timer odpowiedzialna za pomiar temperatury na czujniku
*/
    private final Timer tempSensor;

/** 
* Konstruktor klasy TemperatureService, zawiera 3 parametry.
* Konstruktor ustawia wewnątrz obiektu parametry podane w konstruktorze, ustawia odpowiednią komendę służącą do pomiaru temperatury
* i uruchamia ją jako proces. Następnie jest ustawiane zadanie pomiaru temperatury(przeładowanie funkcji run() ) jako TimerTask.
* Na samym końcu zostaje uruchomione wcześniej ustawione zadanie pomiaru temperatury jako Timer z określoną funkcją run oraz czasem określonym w configu.
* @param conf   - parametr typu LocalConfiuration będący referencją na obiekt zawierający informacje konfiguracyjne.
* @param iface  - parametr typu String zawierający ścieżkę do unixowego dowiązania do urządzenia z czujnikiem(sugerowane ttyS0). Dla dowiązania wymagane sa uprawnienia 'rw'.
* @param index parametr typu int(zmienna index) - oznacza numer identyfikacyjny jeżeli do tego samego interfejsu urządzenia podłaczony jest więcej niż jeden czujnik.
* @throws java.io.IOException
* @throws java.lang.InterruptedException
*/
	public TemperatureService(LocalConfiuration conf, String iface, int index) {
        this.index = index;
		this.shellCommand = "digitemp_DS9097 -t " + index + " -o %.2C -q";
		Process p;
		try {
			p = Runtime.getRuntime().exec("digitemp_DS9097 -i -s /dev/" + iface);
			p.waitFor();
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

        TimerTask task = new TimerTask() {
        	@Override
        	public void run() {
        		try {
					data = getTemperature();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
        	}
        };
        task.run(); // first run for prevent for "null" data
        
        tempSensor = new Timer("Temp sensor thread " + index, true);
        tempSensor.schedule(task, 0, conf.getThreadsTimeout());
	}

    /**
     * @return Zwraca pomiar temperatury jako String lub kod błędu czujnika (oznaczany przez wartość 85)
     * @throws java.lang.InterruptedException
     * @throws java.io.IOException
     */
    private String getTemperature() throws InterruptedException, IOException {
		String s = null;
		String err = null;

        Process p = Runtime.getRuntime().exec(shellCommand);
        p.waitFor();

        // buffer for the measurement
        BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));

        // buffer for errors
        BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));

        s = stdInput.readLine();

        while ((err = stdError.readLine()) != null) {
            System.out.println(err);
        }

        if(s != null)
        	return s;
        else
        	return "85"; // 85 degrees Celsius is the DS1820 sensor's error code
	}
/**
* Metoda zwraca numer indeksu dla czujnika
* @return index Zwraca numer indeksu dla czujnika
*/
    public int getIndex() {
        return index;
    }
/**
* Metoda zwraca zawartość stringa pola data
* @return data  Zwraca zawartość stringa pola data
*/
	
	@Override
	public String getData() {
		return data;
	}
/**
* @return zwraca wartość wyliczeniową TEMP obiektu enum DataType
*/
	@Override
	public DataType getType() {
		return DataType.TEMP;
	}
/**
* @return Zwraca zawsze wartość '1'
*/	
	@Override
	public int getDevId() {
		return 1;
	}
/**
* Metoda zatrzymuje Timer służący do pomiaru temperatury
*/
	public void stopService() {
		tempSensor.cancel();
	}

}
